﻿using AutoMapper;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using WeatheRx.Data;
using WeatheRx.DomainModel.Search;
using WeatheRx.Managers.Search;
using WeatheRx.Managers.Utilities;

namespace WeatheRx.Managers
{
    public interface IApplicantManager
    {
        List<ApplicantSearchResult> Search(string searchTerm);

        List<ApplicantSearchResult> SearchWithMatchCategories(string searchTerm);

        Applicant Get(int applicantId);

        void Store(Applicant applicant, bool includeJob = false);

        List<ApplicantSearchResult> ComprehensiveSearch(ComprehensiveSearchRequestModel model);
    }

    public class ApplicantManager : IApplicantManager
    {
        private IJobManager jobManager { get; set; }

        private IUtilityManager utilityManager { get; set; }

        public ApplicantManager()
        {
            jobManager = new JobManager();
            utilityManager = new UtilityManager();
        }

        public ApplicantManager(IJobManager jm, IUtilityManager um)
        {
            jobManager = jm;
            utilityManager = um;
        }

        public List<ApplicantSearchResult> Search(string searchTerm)
        {
            var results = new List<ApplicantSearchResult>();
            using (var db = new HWAPEntities())
            {
                var result = Mapper.Map<List<ApplicantSearchResult>>(db.Applicants
                    .Where(x => (x.FirstName + " " + x.LastName).Contains(searchTerm) ||
                    (x.StreetNumber + " " + x.StreetOrientation + " " + x.StreetName).Contains(searchTerm) ||
                    (x.Job.OwnerFirstName + " " + x.Job.OwnerLastName).Contains(searchTerm) ||
                    (x.Phone + x.Email + x.Mobile).Contains(searchTerm)
                    ).ToList());
                results.AddRange(result);
            }
            return results;
        }

        public List<ApplicantSearchResult> SearchWithMatchCategories(string searchTerm)
        {
            var results = new List<ApplicantSearchResult>();
            using (var db = new HWAPEntities())
            {
                var applicants = db.Applicants
                    .Where(x => (x.FirstName + " " + x.LastName).Contains(searchTerm) ||
                    (x.StreetNumber + " " + x.StreetOrientation + " " + x.StreetName).Contains(searchTerm) ||
                    (x.Job.OwnerFirstName + " " + x.Job.OwnerLastName).Contains(searchTerm) ||
                    (x.Phone + x.Email + x.Mobile).Contains(searchTerm)
                    ).ToList();
                var result = Mapper.Map<List<ApplicantSearchResult>>(applicants);
                result.ForEach(x => x.MatchedOn = new List<string>());
                result.Where(x => (x.FirstName + " " + x.LastName).Contains(searchTerm)).ToList().ForEach(x => x.MatchedOn.Add("Applicant Name"));
                result.Where(x => (x.StreetNumber + " " + x.StreetOrientation + " " + x.StreetName).Contains(searchTerm)).ToList().ForEach(x => x.MatchedOn.Add("Applicant Address"));
                result.Where(x => (x.Job.OwnerFirstName + " " + x.Job.OwnerLastName).Contains(searchTerm)).ToList().ForEach(x => x.MatchedOn.Add("Owner Name"));
                result.Where(x => (x.Phone + x.Email + x.Mobile).Contains(searchTerm)).ToList().ForEach(x => x.MatchedOn.Add("Applicant Contact Info"));
                results.AddRange(result.OrderByDescending(x => x.MatchedOn != null ? (x.MatchedOn == null ? x.MatchedOn.Count : 0) : 0).ToList());
            }
            return results;
        }

        public List<ApplicantSearchResult> ComprehensiveSearch(ComprehensiveSearchRequestModel model)
        {
            List<ApplicantSearchResult> results;
            using (var db = new HWAPEntities())
            {
                var applicants = db.Applicants
                    .Where(x => (x.StreetNumber + " " + x.StreetOrientation + " " + x.StreetName).Contains(model.StreetAddress) || string.IsNullOrEmpty(model.StreetAddress))
                    .Where(x => (x.LastName).Contains(model.LastName) || string.IsNullOrEmpty(model.LastName))
                    .Where(x => (x.Phone + " " + x.Mobile).Contains(model.PhoneNumber) || string.IsNullOrEmpty(model.PhoneNumber))
                    .Where(x => (true) || string.IsNullOrEmpty(model.OceanId)) //todo add OCEAN number
                    .Where(x => (x.SSN).Contains(model.SSN) || string.IsNullOrEmpty(model.SSN))
                    .Where(x => (x.JobNum).Contains(model.JobNum) || string.IsNullOrEmpty(model.JobNum))
                    .Where(x => (x.Job.Units.Any(y => (y.Inspector.FirstName + " " + y.Inspector.LastName).Contains(model.Inspector))) || string.IsNullOrEmpty(model.Inspector))
                    .Where(x => (x.Job.WorkOrders.Any(y => (y.Contractor.CompanyName.Contains(model.Contractor))) || string.IsNullOrEmpty(model.Contractor)))
                    .ToList();
                results = Mapper.Map<List<ApplicantSearchResult>>(applicants);
            }
            return results;
        }

        public Applicant Get(int applicantId)
        {
            Applicant result;
            using (var db = new HWAPEntities())
            {
                var applicant = db.Applicants.FirstOrDefault(x => x.ApplicantId == applicantId);
                if (applicant == null) return null;
                result = applicant;
            }
            return result;
        }

        public void Store(Applicant applicant, bool includeJob = false)
        {
            if (applicant.ApplicantId > 0)
                Update(applicant);
            else
                Add(applicant);
            if (includeJob)
                jobManager.Store(applicant.Job);
            applicant.Accounts.ToList().ForEach(x => x.ApplicantId = applicant.ApplicantId);
            utilityManager.StoreAccounts(applicant.Accounts.ToList());
            applicant.HouseholdMembers.ToList().ForEach(x => x.ApplicantId = applicant.ApplicantId);
            StoreHouseholdMembers(applicant.HouseholdMembers.ToList());
        }

        private void Update(Applicant applicant)
        {
            using (var db = new HWAPEntities())
            {
                var firstOrDefault = db.Applicants.FirstOrDefault(x => x.ApplicantId == applicant.ApplicantId);
                if (firstOrDefault != null)
                {
                    Mapper.Map(applicant, firstOrDefault);
                }
                else
                {
                    Add(applicant);
                }
                db.SaveChanges();
            };
        }

        private void Add(Applicant applicant)
        {
            using (var db = new HWAPEntities())
            {
                db.Applicants.Add(applicant);
                db.SaveChanges();
            }
        }

        private void StoreHouseholdMembers(List<HouseholdMember> members)
        {
            using (var db = new HWAPEntities())
            {
                var updateList = members.Where(x => x.HouseholdMemberId > 0).ToList();
                var addList = members.Where(x => x.HouseholdMemberId == 0).ToList();

                updateList.ForEach(x =>
                {
                    var firstOrDefault = db.HouseholdMembers.FirstOrDefault(y => y.HouseholdMemberId > 0);
                    if (firstOrDefault != null)
                    {
                        Mapper.Map(x, firstOrDefault);
                    }
                    else
                    {
                        addList.Add(x);
                    }
                });
                db.HouseholdMembers.AddRange(addList);
                db.SaveChanges();
            }
        }
    }
}